package winOrDie.Net.Server;

import java.io.UnsupportedEncodingException;
import java.net.DatagramPacket;
import java.util.Vector;

import winOrDie.Net.WoD_Net_Protocol_ASCII;
import winOrDie.Net.WoD_Net_Protocol_Manager;
import winOrDie.Net.WoD_UDP_Channel;
import winOrDie.Net.WoD_UDP_Channel_Event;
import winOrDie.Net.WoD_UDP_Channel_Listener;


/**
 * This class provides WoD Real time server 
 *
 */
public class WoD_Server_RT 
implements WoD_UDP_Channel_Listener
{
	
	/**
	 * Listeners vector
	 */
	private Vector<WoD_Server_RT_Listener> listeners = null;
	
	/**
	 * WoD UDP Channel
	 */
	WoD_UDP_Channel woDUDPChannel = null;
	
	/**
	 * Wod Protocol manager
	 */
	WoD_Net_Protocol_Manager woDNetProtocolManager = null;
	
	public WoD_Server_RT(
			int serverPort, 
			int bufferLength,
			int timeOut
			)

	{
		// Initialize listener
		listeners = new Vector<WoD_Server_RT_Listener>();
		
		// Initialize Wod protocol manager
		woDNetProtocolManager = new WoD_Net_Protocol_Manager();
		
		// Initialize WoD_UDP_Channel and add this class as listener
		woDUDPChannel = new WoD_UDP_Channel(serverPort, bufferLength, timeOut);
		woDUDPChannel.add_WoD_UDP_Channel_Listener(this);
		
		
	}


	
	public synchronized void add_WoD_Server_RT_Listener(WoD_Server_RT_Listener listener)
	{
		listeners.add(listener);
	}
	
	public synchronized void remove_WoD_Server_RT_Listener(WoD_Server_RT_Listener listener)
	{
		listeners.remove(listener);
	}
	
	protected void fireEvent(WoD_Server_RT_Event event)
	{
		for (WoD_Server_RT_Listener listener : listeners) {
			listener.notify_Event_WoD_Server_RTChannel(event);
		}
	}
	
	
	
	public void startServer() throws Exception
	{
		woDUDPChannel.start_WoD_UDP_Channel();
	}



	private void parse_RT_Message(DatagramPacket datagramPacket)
	{
		WoD_Server_RT_Event event = null;
		try {
			final byte header = woDNetProtocolManager.parse_RT_Header(datagramPacket.getData());
			
			
			switch (header) {
			case WoD_Net_Protocol_ASCII.RealTime.HEADER_SNTP:
				event = new WoD_Server_RT_Event(this);
				event.setEvent_Type(WoD_Server_RT_Event.GAME_NTP);
				event.setData(datagramPacket);
				fireEvent(event);
				break;

			case WoD_Net_Protocol_ASCII.RealTime.HEADER_GAME_ACTION:
				event = new WoD_Server_RT_Event(this);
				event.setEvent_Type(WoD_Server_RT_Event.GAME_ACTION);
				event.setData(datagramPacket);
				fireEvent(event);
				break;				
				
			default:
				event = new WoD_Server_RT_Event(this);
				event.setEvent_Type(WoD_Server_RT_Event.ERROR_PROTOCOL);
				event.setData(datagramPacket);
				fireEvent(event);
				break;
			}
		} catch (Exception e) {
			event = new WoD_Server_RT_Event(this);
			event.setEvent_Type(WoD_Server_RT_Event.ERROR_PROTOCOL);
			event.setData(datagramPacket);
			fireEvent(event);
		}
	}
	
	
	private void parse_RT_Message_STRING(DatagramPacket datagramPacket)
	{
		// Decode the bytes of the packet to characters, using the
        // UTF-8 encoding, and then display those characters.
		String msg = null;
		WoD_Server_RT_Event event = new WoD_Server_RT_Event(this);
		
        try {
			msg = new String(datagramPacket.getData(), 0, datagramPacket.getLength(), "UTF-8");
		} catch (UnsupportedEncodingException e) {
			/*
			 * Fire error event and exit from method
			 */
			
			event.setEvent_Type(WoD_Server_RT_Event.ERROR_DATAGRAM);
			String message = "Datagram Error on datagram. " + e.getMessage();
			event.setMessage(message);
			event.setData(datagramPacket);
			fireEvent(event);
			return;
		}
		
		String header = msg.split(" ")[0];
		
		
		if (header.equals(WoD_Net_Protocol_ASCII.RealTime.HEADER_SNTP))
		{
			event.setEvent_Type(WoD_Server_RT_Event.GAME_NTP);
			event.setData(datagramPacket);
			event.setMessage(msg);
			fireEvent(event);
		}
		else if (header.equals(WoD_Net_Protocol_ASCII.RealTime.HEADER_GAME_ACTION))
		{
			event.setEvent_Type(WoD_Server_RT_Event.GAME_ACTION);
			event.setData(datagramPacket);
			event.setMessage(msg);
			fireEvent(event);
		}
		else
		{
			event.setEvent_Type(WoD_Server_RT_Event.ERROR_PROTOCOL);
			event.setData(datagramPacket);
			fireEvent(event);
		}
        
	}
	
	public void send_Message_To_Client(WoD_Server_Client client, byte[] message) throws Exception
	{
		try {
			woDUDPChannel.send_Message(
					client.getHostDirection(), 
					client.getUdp_port(), 
					message);
		} catch (Exception e) {
			Exception exception = new Exception("Error while sending message to client: " + client.getUserName() + ". " + e.getMessage());
			throw exception;
		}
	}
	
	public void send_Message_To_Client(WoD_Server_Client client, String message) throws Exception
	{
		try {
			woDUDPChannel.send_Message(
					client.getHostDirection(), 
					client.getUdp_port(), 
					message.getBytes());
		} catch (Exception e) {
			Exception exception = new Exception("Error while sending message to client: " + client.getUserName() + ". " + e.getMessage());
			throw exception;
		}
	}

	
	public void on_WoD_UDP_Channel_Change(WoD_UDP_Channel_Event event) 
	{
		switch (event.getEvent_Type()) {
		case WoD_UDP_Channel_Event.MESSAGE_RECEIVED:
//			System.out.println("UDP Message received");
			parse_RT_Message((DatagramPacket)event.getData());
//			parse_RT_Message_STRING((DatagramPacket)event.getData());
			break;
			
		case WoD_UDP_Channel_Event.ERROR:
			WoD_Server_RT_Event event_RtEvent = new WoD_Server_RT_Event(this);
			event_RtEvent.setEvent_Type(WoD_Server_RT_Event.ERROR_DATAGRAM);
			String message = "Datagram Error on UDP Channel. " + (String)event.getData();
			event_RtEvent.setMessage(message);
			fireEvent(event_RtEvent);
			break;			

		default:
			break;
		}
		
	}
	
}
